package Sagittarius.Manager
{
	import flash.display.Bitmap;
	import flash.display.DisplayObjectContainer;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.geom.Point;
	import Sagittarius.VO.EnemyTrackVO;
	
	import com.pblabs.engine.PBE;
	import com.pblabs.engine.debug.Logger;
	import com.pblabs.engine.entity.IEntity;
	import com.pblabs.rendering2D.SimpleSpatialComponent;
	import com.pblabs.rendering2D.SpriteRenderer;
	
	import Sagittarius.VO.LevelVO;
	
	/**************************************************************************
	 * class			GameManager
	 * description		control the gameplay
	 * @author			Aqua
	 *************************************************************************/
	public class GameManager
	{
		
		//---------------------//
		//      Singleton      //
		//---------------------//
		 
		/**************************************************************************
		 * function					instance getter
		 * description				a private function used to enforce singlton
		 * @return	GameManager		singleton instance of this class
		 *************************************************************************/
		public static function get instance():GameManager
		{
			if(null == _instance)
			{
				_instance = new GameManager(singleton);
			}
		
			return _instance;
		}
		
		/**************************************************************************
		 * function				singleton
		 * description			a private function used to enforce singlton
		 *************************************************************************/
		private static function singleton():void
		{
			
		}
		
		
		//---------------------//
		//     Constructor     //
		//---------------------//
		
		/**************************************************************************
		 * function				GameManager
		 * description			constructor of class
		 * @param	s			a private function used to enforce singlton
		 *************************************************************************/
		public function GameManager(s:Function = null):void
		{
			if (singleton != s)
			{
				throw new Error("This is a singleton class!");
			}
		}
		
		
		//----------------//
		//     Getter     //
		//----------------//
		
		/**************************************************************************
		 * function				(getter)currentFrame
		 * description			currentFrame getter
		 *************************************************************************/
		public function get currentFrame():int
		{
			return _frameCount;
		}
		
		
		//-----------------//
		//     Publics     //
		//-----------------//
		
		/**************************************************************************
		 * function				initialize
		 * description			initialize data
		 * @param	stage		main stage of the gameplay, used to contain all 
		 * 						elements
		 * @param	width		the width of the stage
		 * @param	height		the height of the stage
		 *************************************************************************/
		public function initialize(stage:DisplayObjectContainer, width:uint, height:uint):void
		{
			var layerIndex:int;
			
			_stage = stage;
			_width = width;
			_height = height;
			_evtHost = new MovieClip();
			_initialized = true;
			_layers = [];
			
			for (layerIndex = LAYER_BG; layerIndex <= LAYER_BULLET; ++ layerIndex)
			{
				_layers.push(new DisplayObjectContainer());
			}
		}
		
		/**************************************************************************
		 * function				loadLevel
		 * description			load a level to be started
		 * @param	id			the unique id of this level
		 *************************************************************************/
		public function loadLevel(id:String):void
		{
			_currentLevel = ObjectManager.instance.getObj(id) as LevelVO;
		}
		
		/**************************************************************************
		 * function				start
		 * description			start gameplay
		 *************************************************************************/
		public function start():void
		{
			if (! _initialized)
			{
				Logger.print(this, "You must initialize GameManager before start!");
				return;
			}
			if (_isRunning)
			{
				Logger.print(this, "You mustn't start new games before the old one is stopped!");
				return;
			}
			if (null == _currentLevel)
			{
				Logger.print(this, "You must load a level before start!");
				return;
			}
			
			_frameCount = 0;
			
			if (! _evtHost.hasEventListener(Event.ENTER_FRAME))
			{
				_evtHost.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			}
		}
		
		/**************************************************************************
		 * function				pause
		 * description			pause gameplay
		 *************************************************************************/
		public function pause():void
		{
			
		}
		
		/**************************************************************************
		 * function				resume
		 * description			resume gameplay
		 *************************************************************************/
		public function resume():void
		{
			
		}
		
		/**************************************************************************
		 * function				stop
		 * description			stop gameplay
		 *************************************************************************/
		public function stop():void
		{
			if (_evtHost.hasEventListener(Event.ENTER_FRAME))
			{
				_evtHost.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
			}
		}
		
		
		//------------------//
		//     Privates     //
		//------------------//
		
		/**************************************************************************
		 * function				createBgEntity
		 * description			create an entity to store background image
		 *************************************************************************/
		private function createBgEntity():void
		{
			var render:SpriteRenderer;
			
			render = new SpriteRenderer();			
			render.fileName = "";
			render.scene = PBE.scene;
			render.layerIndex = LAYER_BG;
			render.positionProperty = new PropertyReference("@Spatial.position");
			createEntity(ENTITY_BG_NAME, new Point(0, 0), new Point(0, 0));
			PBE.lookupEntity(ENTITY_BG_NAME).addComponent(render, "Render");
		}
		
		/**************************************************************************
		 * function				loadBgImage
		 * description			load background image and add it to stage
		 *************************************************************************/
		private function loadBgImage():void
		{
			var bgImg:Bitmap;
			
			if (null == _layers[LAYER_BG].getChildByName(_currentLevel.bgResId))
			{
				bgImg = ResourceManager.instance.getResource(_currentLevel.bgResId) as Bitmap;
				_layers[LAYER_BG].addChild(bgImg);
			}
		}
		
		/**************************************************************************
		 * function				onEnterFrame
		 * description			handler of enter frame event
		 * @param	e			event parameter
		 *************************************************************************/
		private function onEnterFrame(e:Event):void
		{
			_frameCount ++;
			checkNewEnemy();
		}
		
		/**************************************************************************
		 * function				checkNewEnemy
		 * description			check if there're enemies ready to be added
		 *************************************************************************/
		private function checkNewEnemy():void
		{
			var vo:EnemyTrackVO;
			
			while (_currentLevel.enemies.length)
			{
				vo = _currentLevel.enemies[0];
				
				if (vo.appearFrame == _frameCount)
				{
					
				}
			}
		}
		
		/**************************************************************************
		 * function				clearContainer
		 * description			remove all children of the container
		 * @param	container	container to be cleared
		 *************************************************************************/
		private function clearContainer(container:DisplayObjectContainer):void
		{
			var num:int;
			
			num = container.numChildren;
			while (-- num >= 0)
			{
				container.removeChildAt(num);
			}
		}
		
		/**************************************************************************
		 * function				createEntity
		 * description			create an entity
		 * @param	id			the unique id of the entity
		 * @param	pos			position of entity
		 * @param	size		size of entity
		 *************************************************************************/
		private function createEntity(id:String, pos:Point, size:Point):void
		{
			var entity:IEntity;
			
			entity = PBE.allocateEntity();
			addSpatialComponent(entity, pos, size);
			entity.initialize("id");
		}
		
		/**************************************************************************
		 * function				addSpatialComponent
		 * description			add SimpleSpatialComponent to an entity
		 * @param	entity		entity to add component to
		 * @param	pos			position of entity
		 * @param	size		size of entity
		 *************************************************************************/
		private function addSpatialComponent(entity:IEntity, pos:Point, size:Point):void
		{
			var spatial:SimpleSpatialComponent;
			
			spatial = new SimpleSpatialComponent();
			spatial.position = new Point(pos.x, pos.y);
			spatial.size = new Point(size.x, size.y);
			spatial.spatialManager = PBE.spatialManager;
			entity.addComponent(spatial, "Spatial"); 
		}
		
		
		private static var _instance:GameManager;
		
		private const ENTITY_BG_NAME	:String	= "Entity_Background";
		private const LAYER_BG		:int	= 0;
		private const LAYER_ENEMY	:int	= 1;
		private const LAYER_PLAYER	:int	= 2;
		private const LAYER_BULLET	:int	= 3;
		
		private var _initialized	:Boolean;					// a flag to mark that if the manager has been initialized
		private var _isRunning		:Boolean;					// a flag to mark that if gameplay is running
		private var _stage			:DisplayObjectContainer;	// main stage of the gameplay
		private var _layers			:Array;						// 
		private var _width			:uint;
		private var _height			:uint;
		private var _evtHost		:MovieClip;
		private var _currentLevel	:LevelVO;
		private var _frameCount		:int;
		
	}
	
}